#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cerrno>
#include <cstring>
#include <string>
#include <cassert>

#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>



#include "threadPool/threadPool.hpp"

#define SIZE 1024

// version2.0 多进程版  父进程与客户端进行连接，子进程为客户端提供服务
/* static void service(int servicesock, const uint16_t port, const std::string &ip)
{
    char buffer[SIZE];
    while (true)
    {
        ssize_t n = read(servicesock, buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n]=0;
            std::cout << ip << " " << port << " "
                      << "#" << buffer << std::endl;
        }
        else if (n == 0)//对端关闭
        {
            logMessage(NORMAL,"client quit I quit ,%s,%d",ip.c_str(),port);
            break;
        }
        else
        {
            logMessage(ERROR, "read error");
            break;
        }
        write(servicesock,buffer,sizeof(buffer));
    }
}

class TcpServer
{
private:
    const static int gbacklog = 20;

public:
    TcpServer(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), _listensock(-1)
    {
    }
    void init()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(FATAL, "create socket error %d %s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success,%d", _listensock);
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if (bind(_listensock, (sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error,%d %s", errno, strerror(errno));
            exit(3);
        }
        logMessage(NORMAL, "bind success");
        // TCP是面向连接的，所以在正式通信的时候要先建立连接
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error,%d %s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }
    void start()
    {
       signal(SIGCHLD, SIG_IGN); // 对SIGCHLD，主动忽略SIGCHLD信号，子进程退出的时候，会自动释放自己的僵尸状态
        while (true)
        {
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // 获取新连接
            //有客户端进行连接，父进程就进行连接，没有连接的话父进程就阻塞在这里
            int servicesock = accept(_listensock, (sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(FATAL, "accept error,%d %s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "Link success %d|%d|%s", servicesock, client_port, client_ip.c_str());
            pid_t id = fork();
            assert(id >= 0);
            if (id == 0) // 子进程
            {
                close(_listensock);
                service(servicesock, client_port, client_ip);
                exit(0);
            }
               //waitpid() 不能使用waitpid()让父进程等待子进程，waitpid若为阻塞等待，父进程必须等待当前子进程退出后
               //才能继续执行自己的代码，无法实现多个客户端和服务器同时通信
                close(servicesock);

        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
};
 */

// version2.1 多进程版   子进程再次fork()创建出孙子进程，然后子进程本身退出，此时孙子进程变为孤儿进程，退出情况便由操作系统管理。
// 孙子进程提供服务
/* static void service(int servicesock, const uint16_t port, const std::string &ip)
{
    char buffer[SIZE];
    while (true)
    {
        ssize_t n = read(servicesock, buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n]=0;
            std::cout << ip << " " << port << " "
                      << "#" << buffer << std::endl;
        }
        else if (n == 0)//对端关闭
        {
            logMessage(NORMAL,"client quit I quit ,%s,%d",ip.c_str(),port);
            break;
        }
        else
        {
            logMessage(ERROR, "read error");
            break;
        }
        write(servicesock,buffer,sizeof(buffer));

    }
}

class TcpServer
{
private:
    const static int gbacklog = 20;

public:
    TcpServer(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), _listensock(-1)
    {
    }
    void init()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(FATAL, "create socket error %d %s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success,%d", _listensock);
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if (bind(_listensock, (sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error,%d %s", errno, strerror(errno));
            exit(3);
        }
        logMessage(NORMAL, "bind success");
        // TCP是面向连接的，所以在正式通信的时候要先建立连接
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error,%d %s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }
    void start()
    {

        while (true)
        {
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // 获取新连接
            //有客户端进行连接，父进程就进行连接，没有连接的话父进程就阻塞在这里
            int servicesock = accept(_listensock, (sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(FATAL, "accept error,%d %s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "Link success %d|%d|%s", servicesock, client_port, client_ip.c_str());
            pid_t id = fork();
            assert(id >= 0);
            if (id == 0) // 子进程
            {
                close(_listensock);
               if(fork()>0)//子进程本身
               {
                exit(0);
               }
               service(servicesock,client_port,client_ip);
               exit(0);
            }
               waitpid(id,nullptr,0);//因为子进程创建好后立即就会退出，父进程也不会阻塞
                close(servicesock);

        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
};
*/

// version3 多线程版
/*  static void service(int servicesock, const uint16_t port, const std::string &ip)
{
    char buffer[SIZE];
    while (true)
    {
        ssize_t n = read(servicesock, buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n]=0;
            std::cout << ip << " " << port << " "
                      << "#" << buffer << std::endl;
        }
        else if (n == 0)//对端关闭
        {
            logMessage(NORMAL,"client quit I quit ,%s,%d",ip.c_str(),port);
            break;
        }
        else
        {
            logMessage(ERROR, "read error");
            break;
        }
        write(servicesock,buffer,sizeof(buffer));

    }
    close(servicesock);
}
class threadData
{
    public:
  int servicesock;
  uint16_t port;
  std::string ip;
};

class TcpServer
{
private:
    const static int gbacklog = 20;

public:

   static void* routine(void* args)
    {
        pthread_detach(pthread_self());//线程分离，主线程不用再等待子线程
        threadData*thData=(threadData*)args;
        service(thData->servicesock,thData->port,thData->ip);


    }
    TcpServer(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), _listensock(-1)
    {
    }
    void init()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(FATAL, "create socket error %d %s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success,%d", _listensock);
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if (bind(_listensock, (sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error,%d %s", errno, strerror(errno));
            exit(3);
        }
        logMessage(NORMAL, "bind success");
        // TCP是面向连接的，所以在正式通信的时候要先建立连接
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error,%d %s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }
    void start()
    {

        while (true)
        {
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // 获取新连接
            //有客户端进行连接，父进程就进行连接，没有连接的话父进程就阻塞在这里
            int servicesock = accept(_listensock, (sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(FATAL, "accept error,%d %s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "Link success %d|%d|%s", servicesock, client_port, client_ip.c_str());
            threadData*thData=new threadData();
            thData->servicesock=servicesock;
            thData->ip=client_ip;
            thData->port=client_port;
            //将servicesock,ip,端口号封装在结构体中，当做参数传递给回调函数
            pthread_t th;
            pthread_create(&th,nullptr,routine,(void*)thData);
            //在多线程这里不能关闭线程不使用的文件描述符，因为主线程和子线程共享一份文件描述符表


        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
};
 */

// version4 线程池版
static void service(int servicesock, const uint16_t port, const std::string &ip, const std::string &name)
{
    char buffer[SIZE];
    while (true)
    {
        ssize_t n = read(servicesock, buffer, sizeof(buffer));
        if (n > 0)
        {
            buffer[n] = 0;
            std::cout << name << " " << ip << " " << port << " "
                      << "#" << buffer << std::endl;
        }
        else if (n == 0) // 对端关闭
        {
            logMessage(NORMAL, "client quit I quit ,%s,%d", ip.c_str(), port);
            break;
        }
        else
        {
            logMessage(ERROR, "read error");
            break;
        }
        write(servicesock, buffer, sizeof(buffer));
    }
    close(servicesock);
}

class TcpServer
{
private:
    const static int gbacklog = 20;

public:
    TcpServer(uint16_t port, std::string ip = "")
        : _port(port), _ip(ip), _listensock(-1), _threadPool()
    {
    }
    void init()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            logMessage(FATAL, "create socket error %d %s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success,%d", _listensock);
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if (bind(_listensock, (sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error,%d %s", errno, strerror(errno));
            exit(3);
        }
        logMessage(NORMAL, "bind success");
        // TCP是面向连接的，所以在正式通信的时候要先建立连接
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error,%d %s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "init server success");
    }
    void start()
    {
        _threadPool.run(); // 启动线程池

        while (true)
        {
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            // 获取新连接
            // 有客户端进行连接，父进程就进行连接，没有连接的话父进程就阻塞在这里
            int servicesock = accept(_listensock, (sockaddr *)&src, &len);
            if (servicesock < 0)
            {
                logMessage(FATAL, "accept error,%d %s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "Link success %d|%d|%s", servicesock, client_port, client_ip.c_str());
            task t(servicesock, client_port, client_ip, service); // 创建任务对象
            _threadPool.push_task(t);                             // 任务进任务队列
        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
    ThreadPool<task> _threadPool; // 线程池对象
};
